package top.gytf.unifiedcall.support.producer.response;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import top.gytf.distools.springboot.ConditionalOnProperty;
import top.gytf.unifiedcall.model.exception.builtin.InvalidParameterException;
import top.gytf.unifiedcall.model.exception.builtin.InvalidStateException;
import top.gytf.unifiedcall.model.exception.builtin.OperationUnsupportedException;
import top.gytf.unifiedcall.producer.response.ResponseHandler;
import top.gytf.unifiedcall.producer.response.ResponseHandlerManager;
import top.gytf.unifiedcall.producer.response.ResponseHandlerManagerImpl;
import top.gytf.unifiedcall.producer.support.exception.*;
import top.gytf.unifiedcall.producer.support.wrap.WrapUnifiedResponseHandler;
import top.gytf.unifiedcall.support.producer.UnifiedCallProducerProperties;
import top.gytf.unifiedcall.support.producer.response.UnifiedCallProducerResponseProperties.ExceptionHandler;
import top.gytf.unifiedcall.support.producer.response.UnifiedCallProducerResponseProperties.WrapHandler;

import java.util.List;

import static top.gytf.unifiedcall.support.producer.response.UnifiedCallProducerResponseProperties.Fields.*;

/**
 * Producer的response模块的自动装配
 */
@Slf4j
@RequiredArgsConstructor
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({UnifiedCallProducerResponseProperties.class, UnifiedCallProducerProperties.class})
@ConditionalOnProperty(properties = UnifiedCallProducerResponseProperties.class, name = enable, havingValue = "true", matchIfMissing = true)
public class UnifiedCallProducerResponseAutoConfiguration {
    private final UnifiedCallProducerProperties properties;
    private final UnifiedCallProducerResponseProperties responseProperties;

    /**
     * 通用的异常适配器
     */
    @Bean
    @ConditionalOnProperty(properties = UnifiedCallProducerResponseProperties.class, prefix = exception, name = ExceptionHandler.Fields.enable, havingValue = "true", matchIfMissing = true)
    public ExceptionAdapter commonExceptionAdapters() {
        return new CompositeExceptionAdapter(List.of(
                new ExceptionBindAdapter(),
                new SimpleExceptionAdapter<>(IllegalArgumentException.class, e -> new InvalidParameterException(e.getMessage(), e)),
                new SimpleExceptionAdapter<>(IllegalStateException.class, e -> new InvalidStateException(e.getMessage(), e)),
                new SimpleExceptionAdapter<>(UnsupportedOperationException.class, e -> new OperationUnsupportedException(e.getMessage(), e))
        ), Integer.MAX_VALUE);
    }

    @Bean
    @ConditionalOnProperty(properties = UnifiedCallProducerResponseProperties.class, prefix = exception, name = ExceptionHandler.Fields.enable, havingValue = "true", matchIfMissing = true)
    public ExceptionResponseHandler exceptionResponseHandler(List<ExceptionAdapter> exceptionAdapters) {
        ExceptionHandler exceptionHandlerProperties = responseProperties.getException();
        log.debug("开启Producer/Response/ExceptionHandler, {}", exceptionHandlerProperties);
        return new ExceptionResponseHandler(exceptionAdapters,
                exceptionHandlerProperties.isHasMessageWhenUnknownException(),
                exceptionHandlerProperties.isPrintHandledException());
    }

    @Bean
    @ConditionalOnProperty(properties = UnifiedCallProducerResponseProperties.class, prefix = wrap, name = WrapHandler.Fields.enable, havingValue = "true", matchIfMissing = true)
    public WrapUnifiedResponseHandler wrapUnifiedResponseHandler() {
        log.debug("开启Producer/Response/WrapHandler");
        return new WrapUnifiedResponseHandler();
    }

    @Bean(initMethod = "initialize", destroyMethod = "destroy")
    @ConditionalOnMissingBean(ResponseHandlerManager.class)
    public ResponseHandlerManager responseHandlerManager(List<ResponseHandler> responseHandlers) {
        String activePackage = properties.getActivePackage();
        log.debug("注入默认ResponseHandlerManager, 使用响应处理器：{}, 活动的包：{}", responseHandlers, activePackage);
        return new ResponseHandlerManagerImpl(responseHandlers, activePackage);
    }
}
